#ifndef SEM_HPP
#define SEM_HPP

#define SEM_PATH "/tmp"
#define SEM_PROJ_ID 66
#define numdefault 1
#define GET_SEM (IPC_CREAT)
#define BUILD_SEM (IPC_CREAT | IPC_EXCL | 0666)

#include <iostream>
#include <memory>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include<string>
#include <unistd.h>


class Semaphore
{
public:
    Semaphore(int semid) : _semid(semid)
    {
    }


    ~Semaphore()
    {
        // int n = semctl(_semid, 0, IPC_RMID);
        // if (n < 0)
        // {
        //     std::cerr << "RMID failed!" << std::endl;
        // }
        // std::cout << "RMID sucess!" << std::endl;
    }
    void pv(int data)
    {
        struct sembuf sem_buf;
        sem_buf.sem_num = 0;
        sem_buf.sem_op = data;
        sem_buf.sem_flg = SEM_UNDO;
        int m = semop(_semid, &sem_buf, 1);
    }
    void P()
    {
        pv(-1);
    }
    void V()
    {
        pv(1);
    }

private:
    int _semid;
};

bool Init(int semid, int num = 0)
{
    union semun
    {
        int val;               /* Value for SETVAL */
        struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET  */
        unsigned short *array; /* Array for GETALL, SETALL */
        struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
    } un;
    un.val = 1;
    int ret = semctl(semid, 0, SETVAL, un);
    if (ret < 0)
    {
        std::cerr << "Init failed" << std::endl;
        return false;
    }
    return true;
}
std::string intToHex(int k)
{
    char str[64];
    snprintf(str,sizeof(str),"0x%x",k);
    return std::string(str); 
}
// 建造者模式
class SemaphoreBuilder
{
public:
    SemaphoreBuilder()
    {
    }
    ~SemaphoreBuilder()
    {
    }
    std::shared_ptr<Semaphore> build(int flag, int num = numdefault)
    {
        // 1.构建键值
        key_t k = ftok(SEM_PATH, SEM_PROJ_ID);
        if (k < 0)
        {
            std::cerr << "Ftok failed!" << std::endl;
            return nullptr;
        }
        std::cout<<"k="<<intToHex(k)<<std::endl;
        // 2.创建信号量集合
        int semid = semget(k, num, flag);
        if (semid < 0)
        {
            std::cerr << "Semget failed!" << std::endl;
            return nullptr;
        }
        std::cout << "Get semid:" << semid << std::endl;
        // 3.初始化信号量集合
        if (flag == BUILD_SEM)
            Init(semid, 0);

        return std::make_shared<Semaphore>(semid);
    }


};

#endif // SEM_HPP